package simulator;

import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import simulator.hardware.Computer;
import simulator.software.Kernel;
import simulator.software.Process;
import simulator.software.scheduling.Scheduler;

/**
 * Utility class for the loading of <code>Scenario</code> objects from XML
 * files.
 * 
 * @author Kyle Loomis
 * 
 */
public class ScenarioFileLoader
{
   /**
    * Creates a <code>Scenario</code> based on the XML contained in the provided
    * file.
    * 
    * @param file
    *           the <code>File</code> containing a <code>Scenario</code> in XML
    *           format
    * @return the <code>Scenario</code> described by the file's XML
    */
   public static Scenario loadScenario(File file)
   {
      Random seed = new Random();
      Scenario scenario = null;

      try
      {
         // Parse the XML contained in the file
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         DocumentBuilder builder = factory.newDocumentBuilder();
         Document document = builder.parse(file);

         // Find the root element, which should be a Scenario descriptor
         Element scenarioElement = document.getDocumentElement();

         // Build an instance of a concrete Scenario implementation
         Class scenarioClass = Class.forName(scenarioElement
               .getAttribute("class"));
         scenario = (Scenario) scenarioClass.newInstance();

         // Set the scenario's desription
         scenario.setDescription(scenarioElement.getAttribute("description"));

         // Find all process descriptors, if present
         NodeList processElements = scenarioElement
               .getElementsByTagName("Process");

         // Find all scheduler descriptors, if present
         NodeList schedulerElements = scenarioElement
               .getElementsByTagName("Scheduler");

         // Set the process quantum and average I/O duration
         int quantum = 30;
         int avgIODuration = 40;

         String quantumParam = scenarioElement.getAttribute("quantum");
         String avgIOParam = scenarioElement
               .getAttribute("average_io_duration");

         if (quantumParam != null && quantumParam.length() > 0)
         {
            quantum = Integer.parseInt(quantumParam);
         }

         if (avgIOParam != null && avgIOParam.length() > 0)
         {
            avgIODuration = Integer.parseInt(avgIOParam);
         }

         // Instantiate a computer for this scenario with a single processor
         Computer c = new Computer(1);

         c.setAverageIODuration(avgIODuration);
         Kernel k = new Kernel(c);
         c.setKernel(k);
         k.setCyclesPerQuantum(quantum);
         scenario.setComputer(c);

         // Build processes based on their respective XML elements
         for (int i = 0; i < processElements.getLength(); i++)
         {
            Element processElement = (Element) processElements.item(i);

            String name = processElement.getAttribute("name");
            int steps = Integer.parseInt(processElement.getAttribute("steps"));
            double blockProb = Double.parseDouble(processElement
                  .getAttribute("io"));

            Process p = new Process(name, steps, blockProb, seed);

            String priority = processElement.getAttribute("priority");

            if (priority != null && priority.length() > 0)
            {
               p.setPriority(Integer.parseInt(priority));
            }

            k.addProcess(p);
         }

         if (schedulerElements.getLength() > 0)
         {
            Element schedulerElement = (Element) schedulerElements.item(0);
            String schedulerClassAttrib = schedulerElement
                  .getAttribute("class");
            Class schedulerClass = Class.forName(schedulerClassAttrib);
            Scheduler scheduler = (Scheduler) schedulerClass.newInstance();
            k.setScheduler(scheduler);
         }
      }
      catch (SAXException se)
      {
         se.printStackTrace();
      }
      catch (IOException ioe)
      {
         ioe.printStackTrace();
      }
      catch (ParserConfigurationException pce)
      {
         pce.printStackTrace();
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }

      return scenario;
   }
}
